con



pub start

dat


'-----------[ i2c routines ]--------------------------------------------------

'i2c_waddr: Write address in ee_addr to aux eeprom.

i2c_waddr     call      #i2c_start              'Do start condition.
              mov       acc,#%1010_001_0        'Get write address command in acc.
              call      #i2c_wr                 'Send it.
        if_c  jmp       #i2c_waddr              'Restart if not acknowledged (may be busy writing a page).
        
              mov       acc,ee_addr             'Get high byte of address.
              shr       acc,#8
              call      #i2c_wr                 'Send it.
              mov       acc,ee_addr             'Get low byte of address.
              call      #i2c_wr                 'Send it.
i2c_waddr_ret ret                               'Over and out.

'i2c_rd_nak: Read a byte from eeprom and send NAK.

i2c_rd_nak    test      $,#1 wc                 'Set carry flag (odd parity) for NAK.
              jmp       #i2c_rd

'i2c_rd_ack: Read a byte from eeprom and send ACK.

i2c_rd_ack    test      $,#0 wc                 'Clear carry flag (even parity) for ACK.

'i2c_rd: Read a byte from eeprom and send ACK/NAK based on carry.

i2c_rd        mov       acc,#$ff                'Make sure no zeroes get written.
              jmp       #i2c_rd_wr

'i2c_wr: Write a byte to eeprom, returning ACK in carry.

i2c_wr        test      $,#1 wc                 'Set carry flag (odd parity) to read ACK.

'i2c_byte: Combo read and write byte routine.

i2c_rd_wr     mov       count,#9                'Nine bits, including ACK.
              rcl       acc,#24                 'Get byte into 8 MSBs, and ACK/NAK into next bit.

:wrlp         rcl       acc,#1 wc               'Rotate carry into acc and next write bit out.
              muxnc     dira,sda_pin            'Pull sda low iff carry is clear.
              call      #delay650               'Wait 650ns.
              or        outa,scl_pin            'Drive SCL high.
              call      #delay650               'Wait 650ns.
              test      sda_pin,ina wc          'Get sda pin state into carry (parity). (Last time is ACK/NAK.)
              andn      outa,scl_pin            'Drive SCL low.
              call      #delay650               'Wait 650ns.
              djnz      count,#:wrlp            'Back for next bit.

              and       acc,#$ff                'Acc has data read from i2c; carry has ACK/NAK.
i2c_rd_ack_ret
i2c_rd_nak_ret
i2c_rd_ret
i2c_wr_ret    ret

'i2c_start: Set a start condition.
            
i2c_start     andn      dira,sda_pin            'Let sda float high.
              call      #delay650               'Wait 650ns.
              or        outa,scl_pin            'Drive SCL high.
              or        dira,scl_pin
              call      #delay650               'Wait 650ns.
              or        dira,sda_pin            'Pull sda low.
              call      #delay650               'Wait 650ns.
              andn      outa,scl_pin            'Drive SCL low.
              call      #delay650               'Wait 650ns.
i2c_start_ret ret

'i2c_stop: Set a stop condition.

i2c_stop      andn      outa,scl_pin            'Pull SCL low.
              call      #delay650               'Wait 650ns.
              or        dira,sda_pin            'Pull sda low.
              call      #delay650               'Wait 650ns.
              or        outa,scl_pin            'Drive SCL high.
              call      #delay650               'Wait 650ns.
              andn      dira,sda_pin            'Let sda float high.
              call      #delay650               'Wait 650ns.
              andn      dira,scl_pin            'Let SCL float.
i2c_stop_ret  ret

'-------[ Delay routines. ]-----------------------------------------------------

'delay650: Wait 650 ns.

delay650      mov       adc_timer,#52
              add       adc_timer,cnt
              waitcnt   adc_timer,#0
delay650_ret  ret